#pragma once

#include <iostream>
#include <unistd.h>
#include <functional>
#include "prodconsmod.hpp"

namespace Func_Data
{
    using MyDataType = std::function<void()>;

    template <typename T>
    struct MyData
    {
        const char *_name;
        Prod_Cons_Mod::Block_Queue<T> *_myqueue;
        MyData(const char *name, Prod_Cons_Mod::Block_Queue<T> *myqueue)
            : _name(name), _myqueue(myqueue)
        {
        }
    };

    std::string Description(int a, int b)
    {
        std::string buffer = std::to_string(a) + " + " + std::to_string(b) + " = ";
        return buffer;
    }

    void *producer(void *argv)
    {
        MyData<MyDataType> *myproducer = static_cast<MyData<MyDataType> *>(argv);
        int a = 100;
        int b = 100;
        while (1)
        {
            std::string buffer = std::to_string(a) + " + " + std::to_string(b) + " = ";
            MyDataType add = [buffer, a, b]()
            {
                std ::cout << buffer << (a + b) << std::endl;
            };
            myproducer->_myqueue->Push(&add);
            std::cout << myproducer->_name << " send: " << buffer << std::endl;
            a++;
            b++;
            usleep(5000);
        }
    }

    void *consumer(void *argv)
    {
        MyData<MyDataType> *myconsumer = static_cast<MyData<MyDataType> *>(argv);
        while (1)
        {
            MyDataType data = myconsumer->_myqueue->Pop();
            std::cout << myconsumer->_name << " receive: ";
            data();
            sleep(1);
        }
    }

    void linux_prodcons()
    {
        Prod_Cons_Mod::Block_Queue<MyDataType> *myqueue = new Prod_Cons_Mod::Block_Queue<MyDataType>(5);
        MyData<MyDataType> *myproducer = new MyData<MyDataType>("producer", myqueue);
        MyData<MyDataType> *myconsumer = new MyData<MyDataType>("consumer", myqueue);

        pthread_t pth1_id;
        pthread_create(&pth1_id, NULL, producer, (void *)(myproducer));
        pthread_t pth2_id;
        pthread_create(&pth2_id, NULL, consumer, (void *)(myconsumer));

        pthread_join(pth1_id, nullptr);
        pthread_join(pth2_id, nullptr);

        delete myqueue;
        delete myproducer;
        delete myconsumer;
    }

}